#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
package ${package}.basic.module.role.service.impl;

import ${package}.basic.module.element.mapper.ElementMapper;
import ${package}.basic.module.menu.mapper.MenuMapper;
import ${package}.basic.module.operate.mapper.OperateMapper;
import ${package}.basic.module.permission.mapper.PermissionMapper;
import ${package}.basic.module.role.mapper.RoleMapper;
import ${package}.basic.module.role.service.RoleService;
import ${package}.basic.module.userunionrole.mapper.UserUnionRoleMapper;
import ${package}.common.bean.po.Element;
import ${package}.common.bean.po.ElementPermission;
import ${package}.common.bean.po.Menu;
import ${package}.common.bean.po.MenuPermission;
import ${package}.common.bean.po.Operate;
import ${package}.common.bean.po.OperatePermission;
import ${package}.common.bean.po.Role;
import ${package}.common.bean.po.RolePermission;
import ${package}.common.bean.po.UserUnionRole;
import ${package}.common.bean.vo.Constraint;
import ${package}.common.bean.vo.DistributionRole;
import ${package}.common.bean.vo.QueryBean;
import ${package}.common.bean.vo.SubPermission;
import ${package}.common.bean.vo.UserPermissionVo;
import ${package}.common.emum.PermissionTypeEnum;
import ${package}.common.emum.ReturnCodeEnum;
import ${package}.common.emum.RoleStatusEnum;
import ${package}.common.exception.ValidException;
import ${package}.common.utils.SessionUtil;
import ${package}.common.utils.SnowFlakeUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Description: 无法补充
 *
 * @author wupanhua
 * @date 2019/8/6 15:28
 *
 * <pre>
 *              ${copyright}
 *      Copyright (c) 2019. All Rights Reserved.
 * </pre>
 */
@Service
@Slf4j
@AllArgsConstructor
public class RoleServiceImpl implements RoleService {

    /**
     * 角色Mapper
     */
    private RoleMapper roleMapper;
    /**
     * 用户角色Mapper
     */
    private UserUnionRoleMapper userUnionRoleMapper;
    /**
     * 菜单Mapper
     */
    private MenuMapper menuMapper;
    /**
     * 元素Mapper
     */
    private ElementMapper elementMapper;
    /**
     * 操作Mapper
     */
    private OperateMapper operateMapper;
    /**
     * 权限Mapper
     */
    private PermissionMapper permissionMapper;

    /**
     * Description:
     * <根据用户主键获取角色列表>
     * @author wupanhua
     * @date 10:51 2019/8/7
     * @param id 1
     * @return java.util.List<Role>
     **/
    @Override
    public List<Role> findRolesByUserKey(Long id) {
        return roleMapper.findRolesByUserKey(id);
    }

    /**
     * Description:
     * <获取用户的所有权限>
     * @author 周婷婷
     * @date 10:52 2019/8/7
     * @return java.util.List<UserPermissionVo>
     **/
    @Override
    public List<UserPermissionVo> getPermissionByUserId(){

        //存放用户是所有权限
        List<UserPermissionVo> all = new ArrayList<>();
        //当前用户的角色
        List<Role> roles = roleMapper.findRolesByUserKey(SessionUtil.getUser().getId());
        //没有角色，即没有权限
        if(roles.isEmpty()){
            return Lists.newArrayList();
        }
        //获取该用户的所有操作权限
        List<UserPermissionVo> userPermissOperate = permissionMapper.queryOperatePermissionByRole(roles);
        //获取该用户的所有元素权限
        List<UserPermissionVo> userPermissElement = permissionMapper.queryElementPermissionByRole(roles);

        //组装数据返回
        all.addAll(userPermissOperate);
        all.addAll(userPermissElement);
        return all;
    }

    /**
     * Description:
     * <根据用户主不在的角色>
     * @author wupanhua
     * @date 10:53 2019/8/7
     * @param id 1
     * @return java.util.List<Role>
     **/
    @Override
    public List<Role> findNotInRolesByUserKey(Long id) {

        // 获取所有角色列表
        List<Role> all = roleMapper.findAllRoleIsEnable();

        // 获取当前用户下的角色
        List<Role> current = roleMapper.findRolesByUserKey(id);

        List<Role> dontHas = new ArrayList<>();
        dontHas.addAll(all);
        Set<String> currentNameSet = current.stream().map(Role::getName).collect(Collectors.toSet());

        // 删除不属于用户的角色
        dontHas.removeIf(role-> currentNameSet.contains(role.getName()));
        return dontHas;
    }

    /**
     * 获取所有角色
     * @return
     */
    /**
     * Description:
     * <获取所有角色>
     * @author wupanhua
     * @date 10:53 2019/8/7
     * @return java.util.List<Role>
     **/
    @Override
    public List<Role> findAllRoles() {
        return roleMapper.findAllRoleIsEnable();
    }

    /**
     * Description:
     * <下发角色>
     * @author wupanhua
     * @date 10:54 2019/8/7
     * @param distributionRole 1
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void distributionRole(DistributionRole distributionRole) {

        // 根据用户主键删除角色数据
        userUnionRoleMapper.deleteByUserKey(distributionRole.getId());

        // 插入新数据
        Long [] target = distributionRole.getRoleList();
        if (target.length > 0) {
            UserUnionRole userunionrole = new UserUnionRole();
            List<UserUnionRole> userunionroles = new ArrayList<>();
            for (int i = 0; i < target.length; i++) {
                userunionrole.setId(SnowFlakeUtil.getID());
                userunionrole.setUserId(distributionRole.getId());
                userunionrole.setRoleId(target[i]);
                userunionroles.add(userunionrole);
            }
            userUnionRoleMapper.batchInsert(userunionroles);
        }

    }

    /**
     * Description:
     * <获取角色列表>
     * @author wupanhua
     * @date 10:54 2019/8/7
     * @param queryBean 1
     * @return com.github.pagehelper.PageInfo<Role>
     **/
    @Override
    public PageInfo<Role> findRoleListLimit(QueryBean queryBean) {

        // 筛选状态
        Constraint constraint = Constraint.build()
                .putField("role.status")
                .putOp(Constraint.LOPERATE.IN.getOperation())
                .putValus(Boolean.TRUE, RoleStatusEnum.ENABLED.getCode(), RoleStatusEnum.DISABLE.getCode())
                .putValueType(Constraint.DATATYPE.STRING.getType());
        queryBean.and(constraint);

        Page<Role> page = PageMethod.startPage(queryBean.getCurrent(), queryBean.getPageSize());
        roleMapper.findRoleListLimit(queryBean);

        return new PageInfo<>(page);
    }

    /**
     * Description:
     * <新增角色>
     * @author wupanhua
     * @date 10:54 2019/8/7
     * @param role 1
     **/
    @Override
    public void addRole(Role role){
        roleMapper.insertRole(role);
    }

    /**
     * Description:
     * <根据主键删除角色>
     * @author wupanhua
     * @date 10:55 2019/8/7
     * @param id 1
     **/
    @Override
    public void deleteRoleByRoleKey(Long id){

        // 校验是否有用户占用角色,如果占用则无法被删除
        int count = userUnionRoleMapper.queryUserUnionRoleByRoleId(id);

        if (count != 0){
            throw new ValidException(ReturnCodeEnum.CURRENT_ELEMENT_WAS_OCCUPIED);
        }
        // 删除角色所拥有的权限
        List<RolePermission> permissions = permissionMapper.queryPermissionByRoleKey(id);

        if (permissions != null) {
            for (RolePermission rolePermission: permissions) {
                // 页面元素权限
                if (rolePermission.getPermissionTypeCode().equals(PermissionTypeEnum.MENU.getCode())) {
                    permissionMapper.deleteMenuPermissionByPermissionId(rolePermission.getId());
                }
                // 菜单权限
                if (rolePermission.getPermissionTypeCode().equals(PermissionTypeEnum.ELEMENT.getCode())) {
                    permissionMapper.deleteElementPermissionByPermissionId(rolePermission.getId());
                }
                // 操作链接权限
                if (rolePermission.getPermissionTypeCode().equals(PermissionTypeEnum.OPERATE.getCode())) {
                    permissionMapper.deleteOperatePermissionByPermissionId(rolePermission.getId());
                }
            }
        }
        // 根据角色主键删除角色权限表数据
        permissionMapper.deleteByRoleId(id);
        // 根据主键把角色状态置为删除
        roleMapper.updateRoleStatusDisable(id);
    }

    /**
     * Description:
     * <下发权限>
     * @author wupanhua
     * @date 10:55 2019/8/7
     * @param subPermission 1
     **/
    @Override
    public void distributionPermission(SubPermission subPermission){

        // 判断是否已经存在权限数据
        List<RolePermission> permissions = permissionMapper.queryPermissionByRoleKey(subPermission.getRoleId());
        RolePermission menuPermission = null;
        RolePermission elementPermission = null;
        RolePermission operatePermission = null;
        // 分发角色权限表中的权限类型
        for (RolePermission rolePermission: permissions) {
            // 页面元素权限
            if (rolePermission.getPermissionTypeCode().equals(PermissionTypeEnum.MENU.getCode())) {
                menuPermission = rolePermission;
            }
            // 菜单权限
            if (rolePermission.getPermissionTypeCode().equals(PermissionTypeEnum.ELEMENT.getCode())) {
                elementPermission = rolePermission;
            }
            // 操作链接权限
            if (rolePermission.getPermissionTypeCode().equals(PermissionTypeEnum.OPERATE.getCode())) {
                operatePermission = rolePermission;
            }
        }

        // 插入权限
        if (subPermission.getPermissionCode().equals(PermissionTypeEnum.MENU.getCode())) {
            distributionMenu(subPermission, menuPermission, menuPermission);
        } else if (subPermission.getPermissionCode().equals(PermissionTypeEnum.ELEMENT.getCode())) {
            distributionElement(subPermission, elementPermission, menuPermission);
        } else if (subPermission.getPermissionCode().equals(PermissionTypeEnum.OPERATE.getCode())) {
            distributionOperate(subPermission, operatePermission, menuPermission);
        } else {
            throw new ValidException(ReturnCodeEnum.PARAMETER_NOT_MATCH);
        }

    }
    /**
     * Description:
     * <禁用/启用角色>
     * @author pig
     * @date 10:55 2019/8/7
     * @param role 1
     **/
    @Override
    public void disableOrEnableRole(Role role){
        // 检验角色是否有用户占用
        int count = userUnionRoleMapper.queryUserUnionRoleByRoleId(role.getId());
        // 如果被占用不能被禁用
        if (count != 0){
            throw new ValidException(ReturnCodeEnum.CURRENT_ELEMENT_WAS_OCCUPIED);
        }
        //判断传来的状态更新为相反状态
        if(role.getStatus().intValue() == RoleStatusEnum.ENABLED.getCode().intValue()){
            role.setStatus(RoleStatusEnum.DISABLE.getCode());
        }else {
            role.setStatus(RoleStatusEnum.ENABLED.getCode());
        }
        // 禁用角色
        roleMapper.updateRoleStatus(role);
    }

    /**
     * Description:
     * <根据id查询角色信息>
     * @author wupanhua
     * @date 10:56 2019/8/7
     * @param id 1
     * @return Role
     **/
    @Override
    public Role queryRoleById(Long id){
        return roleMapper.queryRolrById(id);
    }

    /**
     * Description:
     * <根据id更新角色额信息>
     * @author wupanhua
     * @date 10:56 2019/8/7
     * @param role 1
     **/
    @Override
    public void updateRoleById(Role role){
        roleMapper.updateRoleById(role);
    }

    /**
     * Description:
     * <批量删除角色>
     * @author pig
     * @date 10:56 2019/8/7
     * @param keys 1
     * @return java.util.List<Role>
     **/
    @Override
    public List<Role> removeRolesBykeys(List<Long> keys){

        // 区分被用户占用的角色
        List<Long> occupied = new ArrayList<>();
        List<Long> free = new ArrayList<>();
        List<UserUnionRole> userUnionRoles = userUnionRoleMapper.queryUserUnionRoleByRoleIdList(keys);
        for (Long key :keys) {
            boolean flag = false;
            for (UserUnionRole uur: userUnionRoles) {
                if (key.equals(uur.getRoleId())){
                    flag = true;
                    break;
                }
            }
            if (flag) {
                occupied.add(key);
            } else {
                free.add(key);
            }
        }

        if(!free.isEmpty()) {
            // 区分菜单权限
            List<RolePermission> permissions = permissionMapper.queryPermissionByRoleKeys(free);
            // 删除角色权限下的子权限
            deleteDifferPermission(permissions);

            // 根据角色主键删除角色权限表数据
            permissionMapper.deleteRolePermissionByRoleIds(free);

            // 将角色状态置为删除
            roleMapper.updateRoleStatusDeleteBykeys(free);
        }

        if(!occupied.isEmpty()) {
            // 获取到不能被删除的角色信息
            return roleMapper.findRoleByRoleKeyList(occupied);
        }else {
            return Lists.newArrayList();
        }
    }

    /**
     * Description:
     * <查询是否重复名称>
     * @author pig
     * @date 10:57 2019/8/7
     * @param name 1
     * @param id 2
     * @return java.lang.Boolean
     **/
    @Override
    public Boolean roleVerifyName(String name, Long id){

        if (id == null){
	        return CollectionUtils.isEmpty(roleMapper.findRolrByName(name));
        } else {
	        return CollectionUtils.isEmpty(roleMapper.findRolrByNameOrNotInId(new Role(id, name)));
        }
    }

    /**
     * Description:
     * <查询编码是否重复>
     * @author pig
     * @date 10:57 2019/8/7
     * @param code 1
     * @return java.lang.Boolean
     **/
    @Override
    public Boolean roleVerifyCode(String code){

	    return CollectionUtils.isEmpty(roleMapper.findRoleByCode(code));
    }

    /**
     * Description:
     * <查询全部角色名称>
     * @author yangliu
     * @date 10:58 2019/8/7
     * @return java.util.List<java.lang.String>
     **/
    @Override
    public List<String> queryAllRoleName() {
        return roleMapper.queryAllRoleName();
    }

    /**
     * Description:
     * <根据角色权限删除其下的子权限>
     * @author wupanhua
     * @date 10:58 2019/8/7
     * @param permissions 1
     **/
    private void deleteDifferPermission(List<RolePermission> permissions) {

        Map<String, List<Long>> result = diffPermission(permissions);

        if (CollectionUtils.isNotEmpty(result.get(PermissionTypeEnum.MENU.getCode()))) {
            permissionMapper.deleteMenuPermissionByPermissionIds(result.get(PermissionTypeEnum.MENU.getCode()));
        }
        if (CollectionUtils.isNotEmpty(result.get(PermissionTypeEnum.ELEMENT.getCode()))) {
            permissionMapper.deleteElementPermissionByPermissionIds(result.get(PermissionTypeEnum.ELEMENT.getCode()));
        }
        if (CollectionUtils.isNotEmpty(result.get(PermissionTypeEnum.OPERATE.getCode()))) {
            permissionMapper.deleteOperatePermissionByPermissionIds(result.get(PermissionTypeEnum.OPERATE.getCode()));
        }
    }

    /**
     * Description:
     * <根据权限类型区分权限>
     * @author wupanhua
     * @date 10:58 2019/8/7
     * @param permissions 1
     * @return java.util.Map<java.lang.String,java.util.List<java.lang.Long>>
     **/
    private Map<String, List<Long>> diffPermission(List<RolePermission> permissions) {

        List<Long> mp = new ArrayList<>();
        List<Long> ep = new ArrayList<>();
        List<Long> op = new ArrayList<>();
        for (RolePermission rolePermission: permissions) {
            // 页面元素权限
            if (rolePermission.getPermissionTypeCode().equals(PermissionTypeEnum.MENU.getCode())) {
                mp.add(rolePermission.getId());
            }
            // 菜单权限
            if (rolePermission.getPermissionTypeCode().equals(PermissionTypeEnum.ELEMENT.getCode())) {
                ep.add(rolePermission.getId());
            }
            // 操作链接权限
            if (rolePermission.getPermissionTypeCode().equals(PermissionTypeEnum.OPERATE.getCode())) {
                op.add(rolePermission.getId());
            }
        }

        Map<String, List<Long>> result = Maps.newHashMap();
        result.put(PermissionTypeEnum.MENU.getCode(), mp);
        result.put(PermissionTypeEnum.ELEMENT.getCode(), ep);
        result.put(PermissionTypeEnum.OPERATE.getCode(), op);

        return result;
    }

    /**
     * Description:
     * <分配菜单权限>
     * @author wupanhua
     * @date 10:59 2019/8/7
     * @param subPermission 1
     * @param rolePermission 2
     * @param m 3
     **/
    private void distributionMenu(SubPermission subPermission, RolePermission rolePermission, RolePermission m){

        if (rolePermission == null) {
            rolePermission = new RolePermission(SnowFlakeUtil.getID(), subPermission.getRoleId(), PermissionTypeEnum.MENU.getCode());
            permissionMapper.insertRolePermission(rolePermission);
        }

        // 判断库中是否有此菜单
        Menu menu = menuMapper.queryMenuByMenuKey(subPermission.getKey());
        if (menu == null) {
            throw new ValidException(ReturnCodeEnum.PARAMETER_NOT_MATCH);
        }

        // 下发或者取消菜单权限
        if (Boolean.TRUE.equals(subPermission.getHasPermission())) {
            permissionMapper.insertMenuPermission(new MenuPermission(SnowFlakeUtil.getID(), rolePermission.getId(),subPermission.getKey()));
            m = rolePermission;
            // 递归下发菜单权限
            distributionMenuCircle(menu.getId(), m, subPermission.getRoleId());
        } else {
            permissionMapper.deleteMenuPermissionByMenuKeyAndPermissionKey(subPermission.getKey(), rolePermission.getId());
        }
    }


    /**
     * Description:
     * <分配元素权限>
     * @author wupanhua
     * @date 10:59 2019/8/7
     * @param subPermission 1
     * @param rolePermission 2
     * @param m 3
     **/
    private void distributionElement(SubPermission subPermission, RolePermission rolePermission, RolePermission m){

        if (rolePermission == null) {
            rolePermission = new RolePermission(SnowFlakeUtil.getID(), subPermission.getRoleId(), PermissionTypeEnum.ELEMENT.getCode());
            permissionMapper.insertRolePermission(rolePermission);
        }

        // 判断是否匹配数据
        Element element = elementMapper.queryElementByElementKey(subPermission.getKey());
        if (element == null) {
            throw new ValidException(ReturnCodeEnum.PARAMETER_NOT_MATCH);
        }

        // 分配用户权限
        if (Boolean.TRUE.equals(subPermission.getHasPermission())) {
            permissionMapper.insertElementPermission(new ElementPermission(SnowFlakeUtil.getID(), rolePermission.getId(), subPermission.getKey()));
            // 递归下发菜单权限
            distributionMenuCircle(element.getMenuId(), m, subPermission.getRoleId());
        } else {
            permissionMapper.deleteElementPermissionByPermissionKeyAndElementKey(subPermission.getKey(), rolePermission.getId());
        }
    }

    /**
     * Description:
     * <分配操作链接权限>
     * @author wupanhua
     * @date 10:59 2019/8/7
     * @param subPermission 1
     * @param rolePermission 2
     * @param m 3
     **/
    private void distributionOperate(SubPermission subPermission, RolePermission rolePermission, RolePermission m){

        if (rolePermission == null) {
            rolePermission = new RolePermission(SnowFlakeUtil.getID(), subPermission.getRoleId(), PermissionTypeEnum.OPERATE.getCode());
            permissionMapper.insertRolePermission(rolePermission);
        }

        Operate operate = operateMapper.queryOperateByOperateKey(subPermission.getKey());
        if (operate == null) {
            throw new ValidException(ReturnCodeEnum.PARAMETER_NOT_MATCH);
        }

        // 分配操作链接权限
        if (Boolean.TRUE.equals(subPermission.getHasPermission())) {
            permissionMapper.insertOperatePermission(new OperatePermission(SnowFlakeUtil.getID(), rolePermission.getId(), subPermission.getKey()));
            // 递归下发菜单权限
            distributionMenuCircle(operate.getMenuId(), m, subPermission.getRoleId());
        } else {
            permissionMapper.deleteOperatePermissionByPermissionKeyAndOperateKey(subPermission.getKey(), rolePermission.getId());
        }
    }

    /**
     * Description:
     * <递归下发菜单权限>
     * @author wupanhua
     * @date 11:00 2019/8/7
     * @param menuKey 1
     * @param m 2
     * @param roleKey 3
     **/
    private void distributionMenuCircle(Long menuKey, RolePermission m, Long roleKey){

        if (m == null) {
            m = new RolePermission(SnowFlakeUtil.getID(), roleKey, PermissionTypeEnum.MENU.getCode());
            permissionMapper.insertRolePermission(m);
        }

        // 判断菜单权限表是否有此菜单权限
        int isOccu = permissionMapper.queryMenuPermissionNumberByMenuKeyAndRolePermKey(menuKey, m.getId());
        if (isOccu == 0) {
            // 下发菜单权限
            permissionMapper.insertMenuPermission(new MenuPermission(SnowFlakeUtil.getID(), m.getId(), menuKey));
            // 获得此菜单的父级菜单
            Menu menu = menuMapper.queryMenuById(menuKey);
            // 下发父级菜单权限
            if (menu.getParentid() != null && menu.getParentid() != 0) {
                distributionMenuCircle(menu.getParentid(), m, roleKey);
            }
        }
    }
}
